﻿using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Data;
using System.Xml;
using System.Windows.Forms;
using PluginInterface;
using SdmxMl.GenericMetadata;
using SdmxMl.Manager;
using SdmxMl.Common;
using SdmxMl.Structure;
using SdmxMl.SanteSuisse;
using SdmxMl.Helper;
using SdmxMl.Multiplexor;
using SilcQuest.CSV;
using SilcQuest.Grid;

namespace SilcQuest
{
    /// <summary>
    /// CATI Plug-In user control, allows PDF like view of question, provide specific menus
    /// </summary>
    public partial class UcCati : UserControl, IPlugin
    {
        #region Internal Members

        private SmManager smCati;
        private MetadataSetType _metadataSet;
        private MetadataStructureDefinitionType _msd;
        private AttributeValueSetType _attributeValueSet;
        private bool isCATI;
        private Dictionary<string, string> dicoCheckedOut;
        private int MaxCodesInPdf;
        private bool closeEventRecorded;
        private SilcGroupInfo silcGroup;

        //Suivi
        MetadataSetType metaSetSuivi;
        MetadataStructureDefinitionType msdSuivi;

        #endregion

        #region C'tor

        public UcCati()
        {
            InitializeComponent();

            //Record event for selection change in main application tree
            ReferenceManager.TreeMgr.TreeSelect += new EventHandler(TreeMgr_TreeSelect); 

            // Init
            EditGroupButtonState(false);
            dicoCheckedOut = new Dictionary<string, string>();
            MaxCodesInPdf = 30;
            closeEventRecorded = false;
            silcGroup = new SilcGroupInfo();

            UpdateMenuState();
        }
        #endregion

        #region Main tree selection changed Event

        /// <summary>
        /// Selection Event in main tree. Uses it to define if HTML CATI is to be displayed
        /// </summary>
        void TreeMgr_TreeSelect(object sender, EventArgs e)
        {
            TreeView tv = ReferenceManager.TreeSdmx;
            if (tv == null)
                return;

            // First time, record for user close event
            if (closeEventRecorded == false)
            {
                ReferenceManager.TreeMgr.UserQuitEventExposed += new UserQuitEvent(TreeMgr_UserQuitEventExposed);
                closeEventRecorded = true;
            }

            // Fetch metaset info is currently selected in main tree
            _attributeValueSet = null;
            try
            {
                // Ic our cache not yet created, make it copy of application main cache
                if (smCati == null)
                    smCati = ReferenceManager.GetSmContainerImage();

                buttonCheckOut.Enabled = false;
                isCATI = false;

                if (tv.SelectedNode != null)
                {
                    _attributeValueSet = tv.SelectedNode.Tag as AttributeValueSetType;
                    // At generic metadata set level, we identify also if set is CATI
                    if (tv.SelectedNode.Tag is MetadataSetType)
                    {
                        _metadataSet = tv.SelectedNode.Tag as MetadataSetType;
                        isCATI = _metadataSet.AnnotationList.GetAnnotationType(SilcGroupInfo.ANNOT_TYPE_CATI) != null;
                    }

                    if (_attributeValueSet != null)
                    {
                        // Required for managing: an annotation with CATI type
                        _metadataSet = _attributeValueSet.ParentMetadataSet;
                        isCATI = _metadataSet.AnnotationList.GetAnnotationType(SilcGroupInfo.ANNOT_TYPE_CATI) != null;
                        if (isCATI)
                        {
                            using (new CWaitCursor())
                            {
                                // Fetch definition (should be in main application memory)
                                _msd = ReferenceManager.LocateMetadataStructureDefinition(_metadataSet.MetadataStructureRef);
                                ReferenceManager.RefreshSmWithContainerImage(smCati);

                                // Ensure suivi history loaded
                                string suiviId = _metadataSet.Id;
                                if (suiviId.StartsWith(silcGroup.GmdStarter))
                                    suiviId = _metadataSet.Id.Substring(silcGroup.GmdStarter.Length);
                                else
                                    suiviId = silcGroup.FilterMsId(suiviId);

                                string metaSuiviId = silcGroup.GmdStarter + SilcGroupInfo.SUIVI_MARKER + suiviId;

                                metaSetSuivi = smCati.GetArtefact(SdmxArtefactType.MetadataSet, 
                                    new ArtefactRefBase(metaSuiviId, this.silcGroup.AgencyId, "1.0"), true) as MetadataSetType;
                                msdSuivi = smCati.GetArtefact(SdmxArtefactType.MetadataStructureDefinitions, 
                                    metaSetSuivi.MetadataStructureRef, true) as MetadataStructureDefinitionType;
                                smCati.LoadMissingArtefactsFromRegistry(msdSuivi.ArtefactRefList);

                                ledBulb.On = dicoCheckedOut.ContainsKey(metaSetSuivi.FullIdent);
                                EditGroupButtonState(ledBulb.On);

                                buttonCheckOut.Enabled = true;
                            }
                        }
                    }

                    // Update plug-in display
                    UpdateMenuState();
                    DisplayCATI();
                    DisplaySuivi();
                }
            }

            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void UpdateMenuState()
        {
            toolStripButtonExportQuestInCsv.Enabled = isCATI;
            toolStripButPdf.Enabled = isCATI;
            toolStripButtonHistoryExport.Enabled = isCATI;
            toolStripButtonRenumber.Enabled = isCATI;

            updateToolStripMenuItem.Enabled = isCATI;
            exportToolStripMenuItem.Enabled = isCATI;
        }

        #endregion

        #region IPlugin Members

        public event PluginEvent PluginEventExposed;

        public void Init(XmlDocument xDoc, object obExtend)
        {
            
        }

        public UserControl VisualComponent()
        {
            return this;
        }

        public bool RequiresInit
        {
            get { return false; }
        }

        #endregion

        #region CATI HTML Display

        /// <summary>
        /// Displays an HTML view of question similar to PDF print-out
        /// </summary>
        private void DisplayCATI()
        {
            try
            {
                if (isCATI && _attributeValueSet != null)
                {
                    SdmxMl.SanteSuisse.SilcCatiHtml sch = new SdmxMl.SanteSuisse.SilcCatiHtml(_metadataSet, smCati);
                    string html = sch.GenerateRowHtml(smCati, _attributeValueSet, LangSupport.CurLang);
                    if (webBrowser.Document != null)
                    {
                        webBrowser.Document.OpenNew(true);
                        webBrowser.Document.Write(html);
                    }
                    else
                    {
                        webBrowser.DocumentText = html;
                    }
                    toolStripTextBoxInfoQuest.Text = _metadataSet != null ? _metadataSet.FullIdent : string.Empty;

                }
                else
                {
                    this.webBrowser.Navigate("about:blank");
                    HtmlDocument doc = this.webBrowser.Document;
                    doc.Write(string.Empty);
                    toolStripTextBoxInfoQuest.Text = string.Empty;
                }
            }
            catch
            {
            }
        }
        #endregion

        #region History trace display

        /// <summary>
        /// Display associated history trace of selected question
        /// </summary>
        private void DisplaySuivi()
        {
            try
            {
                SuiviTableForVariable suiviTableGen = new SuiviTableForVariable();
                dataGridViewHistory.DataSource = 
                    suiviTableGen.Generate(smCati, msdSuivi, metaSetSuivi,
                    (isCATI) ? _attributeValueSet : null);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        #endregion

        #region Print PDF

        /// <summary>Defines maximum number of codes to include in PDF information </summary>
        /// <param name="sender"></param><param name="e"></param>
        private void maxCodesInPdfToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DlgMaxCodes aDlg = new DlgMaxCodes();
            aDlg.MaxCodes = MaxCodesInPdf;
            if (aDlg.ShowDialog() == DialogResult.OK)
                MaxCodesInPdf = aDlg.MaxCodes;
        }

        /// <summary>Print PDF of questionnaire</summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void toolStripButPdf_Click(object sender, EventArgs e)
        {
            try
            {
                if (ReferenceManager.TreeSdmx.SelectedNode != null && _metadataSet != null)
                {
                    if (saveFileDialog.ShowDialog() == DialogResult.OK)
                    {
                        PdfQuest pdf = new PdfQuest(smCati, MaxCodesInPdf);
                        pdf.Generate(saveFileDialog.FileName, _metadataSet.FullIdent, LangSupport.CurLang);
                    }
                }
                else
                {
                    MessageBox.Show("No Questionnaire metadata selected!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        #endregion

        #region Web Browser Navigate

        /// <summary>
        /// If event URL is an SDMX url artefact part, try to navigate to it 
        /// </summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void webBrowser_Navigating(object sender, WebBrowserNavigatingEventArgs e)
        {
            ArtefactRefTyped art = null;

            UrnParser p = new UrnParser(e.Url.ToString());
            if (p.IsSupported)
            {
                try
                {
                    art = new ArtefactRefTyped(p.ArType, p.ArtefactId, p.AgencyId, p.Version);
                    // If already in memory, navigate otherwhile get from regidtry
                    if (NavigationManager.LocatenavigateProject(SdmxArtefactType.Concepts, art.FullIdent, p) == null)
                        NavigationManager.NavigateWithRegistry(SdmxArtefactType.Concepts, art.FullIdent, true, p);
                    e.Cancel = true;
                }
                catch { }
            }
        }
        #endregion

        #region Manage History Edition

        /// <summary>Find history row selected in grid view</summary>
        /// <returns>the datarow or null</returns>
        private DataRow FindSelectedRow()
        {
            DataRow findRow = null;
            if (dataGridViewHistory.DataSource != null && dataGridViewHistory.CurrentRow != null)
            {
                DataRowView drv = dataGridViewHistory.CurrentRow.DataBoundItem as DataRowView;
                if (drv != null)
                    findRow = drv.Row;
            }

            return findRow;
        }

        private void EditRow()
        {
            DataRow findRow = FindSelectedRow();
            if (findRow != null)
            {
                // locate attributevalueSet
                AttributeValueSetType atrTarget = LocateSuiviFromId(findRow["id"].ToString());

                if (atrTarget != null)
                {
                    CatiSuiviItem suiviItem = new CatiSuiviItem(smCati, msdSuivi.ReportStructureList[0], atrTarget);
                    DlgSuivi aDlg = new DlgSuivi(suiviItem, butAdd.Enabled == false);
                    if (aDlg.ShowDialog(this) == DialogResult.OK)
                    {
                        //Update datagrid history
                        findRow["Date"] = suiviItem.Date;
                        findRow["FieldType"] = suiviItem.FieldType;
                        findRow["Problem"] = suiviItem.Problem;
                        findRow["Lang"] = suiviItem.Lang;
                        findRow["Uid"] = suiviItem.User;
                        findRow["TrStat"] = suiviItem.TranslationStatus;
                    }
                }
            }
        }

        /// <summary> Edit selected suivi item </summary>
        /// <param name="sender"></param><param name="e"></param>
        private void butEdit_Click(object sender, EventArgs e)
        {
            EditRow();
        }

        private void butRemove_Click(object sender, EventArgs e)
        {
            DataRow findRow = FindSelectedRow();
            if (findRow != null && _attributeValueSet != null)
            {
                if (MessageBox.Show(this, "Erase selected history note?", "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {

                    // locate attributevalueSet
                    AttributeValueSetType atrTarget = LocateSuiviFromId(findRow["id"].ToString());

                    //Remove it
                    if (atrTarget != null)
                        metaSetSuivi.AttributeValueSetList.Remove(atrTarget);

                    //Update datagrid history
                    DisplaySuivi();
                }
            }

        }

        private void butAdd_Click(object sender, EventArgs e)
        {
            if (_attributeValueSet == null)
                return;


                // Create new attributevalueSet
                AttributeValueSetType suiviAt = new AttributeValueSetType(msdSuivi, msdSuivi.ReportStructureList[0], metaSetSuivi);
                // fills keys
                CatiSilcQuestion question = new CatiSilcQuestion(new RefVarHelper(smCati), _attributeValueSet, LangSupport.CurLang);
                // Keys
                string newId = CreateSuiviId().ToString();
                suiviAt.TargetValuesTypeList.SetComponentValue("ID", newId);
                
                suiviAt.TargetValuesTypeList.SetComponentValue("QUEST_TYPE", question.QuestType);
                suiviAt.TargetValuesTypeList.SetComponentValue("VARNAME", question.VarName);
                suiviAt.TargetValuesTypeList.SetComponentValue("DT", DateTime.Now.ToString("yyyy-MM-dd"));
                suiviAt.TargetValuesTypeList.SetComponentValue("TECH", IsTechnical() ? "1" : "2");

                // Reported values
                SetRepAttValue(suiviAt, "PROBLEM", null);
                SetRepAttValue(suiviAt, "LANG", null);
                SetRepAttValue(suiviAt, "USER", null);
                SetRepAttValue(suiviAt, "FIELD_TYPE", null);

                metaSetSuivi.AttributeValueSetList.Add(suiviAt);
                
                //Update datagrid history
                DisplaySuivi();
                foreach (DataGridViewRow dr in dataGridViewHistory.Rows)
                {
                    foreach (DataGridViewCell cell in dr.Cells)
                        cell.Selected = false;
                    dr.Selected = false;

                    // Select created
                    if (dr.Cells[dr.Cells.Count-1].Value.ToString() == newId)
                    {
                        dataGridViewHistory.CurrentCell = dr.Cells[0];
                        dr.Selected = true;
                    }
                }

                EditRow();
        }


        private void SetRepAttValue(AttributeValueSetType at, string conceptId, MultiLang ml)
        {
            ReportedAttributeType ra = at.ReportedAttributeList.GetReportedAttributeOfConcept(conceptId);
            if (ra != null)
                ra.Value = ml == null ? new MultiLang() : ml;
        }

        private bool IsTechnical()
        {
            return _metadataSet.Id.StartsWith("GMD_TECH_");
        }

        private int CreateSuiviId()
        {
            int id = 1;
            foreach (AttributeValueSetType avs in metaSetSuivi.AttributeValueSetList)
            {
                ComponentValueType compo = avs.TargetValuesTypeList.GetComponentValue("ID");
                if (compo != null)
                {
                    int curId = Convert.ToInt32(compo.Value);
                    if (curId >= id)
                        id = curId + 1;
                }
            }
            return id;
        }

        private AttributeValueSetType LocateSuiviFromId(string id)
        {
            AttributeValueSetType atRet = null;
            foreach (AttributeValueSetType avs in metaSetSuivi.AttributeValueSetList)
            {
                ComponentValueType compo = avs.TargetValuesTypeList.GetComponentValue("ID");
                if (compo != null)
                {

                    string curId = compo.Value;
                    if (curId == id)
                    {
                        atRet = avs;
                        break;
                    }
                }
            }
            return atRet;
        }

        /// <summary>Set state of trace history edition</summary>
        /// <param name="enable">if true, enable buttons</param>
        private void EditGroupButtonState(bool enable)
        {
            //butEdit.Enabled = enable;
            butEdit.Enabled = true;
            butAdd.Enabled = enable;
            butRemove.Enabled = enable;

        }
        #endregion

        #region Checkin/checkout of history generic metadataset

        /// <summary> Reserve associated history tracong generic metadataset </summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void buttonCheckOut_Click(object sender, EventArgs e)
        {
            if (Mux.Instance.State == MultiplexorState.OnError || _attributeValueSet == null)
                return;

            try
            {
                using (new CWaitCursor())
                {
                    if (dicoCheckedOut.ContainsKey(metaSetSuivi.FullIdent) == false)
                    {
                        // Reserve suivi
                        Mux.Instance.CheckOut(SdmxArtefactType.MetadataSet.ToString(), metaSetSuivi.FullIdent);

                        //Ask if refresh needed

                        //memo check out
                        dicoCheckedOut.Add(metaSetSuivi.FullIdent, null);
                        // signal 
                        ledBulb.On = true;

                    }
                    else
                    {
                        // ask if cancel reservation only

                        // submit updated
                        SmManager smTemp = new SmManager();
                        smTemp.PutArtefact(SdmxArtefactType.MetadataSet, metaSetSuivi);
                        XmlDocument xDoc = smTemp.GetMetasetAsDocument(metaSetSuivi.FullIdent);
                        Mux.Instance.SubmitArtefact(SdmxArtefactType.MetadataSet.ToString(), metaSetSuivi.FullIdent, xDoc);

                        //remove from dico
                        dicoCheckedOut.Remove(metaSetSuivi.FullIdent);
                        ledBulb.On = false;
                    }

                    EditGroupButtonState(ledBulb.On);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Event Raised from main application, the plug-in can cancel the Quit command if required
        /// </summary>
        /// <param name="sender"></param> <param name="e"></param>
        void TreeMgr_UserQuitEventExposed(object sender, CancelEventArgs e)
        {
            bool autoCheckin = dicoCheckedOut.Count > 0;
            // If suivi remains checked out, informs user and cancel quit
            if (autoCheckin)
            {
                MessageBox.Show("Some history tracing are reserved. They will be checked in before leaving application.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);

                using (new CWaitCursor())
                {
                    List<string> listFullId = new List<string>(dicoCheckedOut.Keys);
                    foreach (string fullId in listFullId)
                    {
                        ArtefactRefTyped art = new ArtefactRefTyped(SdmxArtefactType.MetadataSet, fullId);
                        dicoCheckedOut.Remove(fullId);
                        metaSetSuivi = smCati.GetArtefact(art) as MetadataSetType;
                        if (metaSetSuivi != null && Mux.Instance.RunningOK)
                        {
                            try
                            {
                                // submit updated
                                SmManager smTemp = new SmManager();
                                smTemp.PutArtefact(SdmxArtefactType.MetadataSet, metaSetSuivi);
                                XmlDocument xDoc = smTemp.GetMetasetAsDocument(metaSetSuivi.FullIdent);
                                Mux.Instance.SubmitArtefact(SdmxArtefactType.MetadataSet.ToString(), metaSetSuivi.FullIdent, xDoc);
                            }
                            catch
                            {
                                // ignore if already checked in by main open application
                            }
                        }
                    }
                    // signal 
                    ledBulb.On = false;
                }
            }
        }


        #endregion

        #region Renumbering questions

        /// <summary>
        /// Redefine year and renumber questions according to tree order
        /// </summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void toolStripButtonNewYear_Click(object sender, EventArgs e)
        {
            try
            {
                if (ReferenceManager.TreeSdmx.SelectedNode != null && _attributeValueSet != null && isCATI)
                {
                    YearAndOrder ynReorder = new YearAndOrder();
                    if (ynReorder.ProcessChange(ReferenceManager.TreeSdmx.SelectedNode, _metadataSet))
                    {
                        // Refresh tree
                        TreeViewUpdateLang(ReferenceManager.TreeSdmx.SelectedNode.Parent);
                        ReferenceManager.TreeMgr.RefreshDetailView();
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        
        /// <summary>
        /// Refresh tree nodes text according to current language
        /// </summary>
        /// <param name="node"></param>
        private void TreeViewUpdateLang(TreeNode node)
        {
            if (node.Tag != null)
                node.Text = node.Tag.ToString();

            foreach (TreeNode n in node.Nodes)
                TreeViewUpdateLang(n);
        }
        #endregion

        #region Export History 

        /// <summary> Export History tracing in a CSV file </summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void toolStripButtonExportCsv_Click(object sender, EventArgs e)
        {
            try
            {
                ToolStripItem tsItem = sender as ToolStripItem;

                if (tsItem != null && Mux.Instance.RunningOK)
                {
                    bool history = tsItem.Tag != null && tsItem.Tag.ToString() == "History";

                    DlgCsvHistoryParam aDlg = new DlgCsvHistoryParam(smCati, history);
                    aDlg.ShowDialog(this);
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        #endregion

        #region Multi Load managment

        private void selectQuestToLoadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                DlgLoadQuest aDlg = new DlgLoadQuest(smCati, PluginEventExposed);
                aDlg.ShowDialog();
            }
            catch (Exception ex)
            {
                MessageBox.Show("An error occured during load phase. Reason: " + ex.Message, 
                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }
        #endregion

        private void toolStripButGridImport_Click(object sender, EventArgs e)
        {
            try
            {
                using (new SdmxMl.Helper.CWaitCursor())
                {
                }
                /* TODO when grid migration occurs
                SakeDsd sd = new SakeDsd();
                sd.AddQualityAttributes();
                 * */
                /*
                ChopCodes chop = new ChopCodes();
                chop.ConstructCodes();
                */
                /*
                IntegrityHeader intHeader = new IntegrityHeader(smCati, 2012, true);
                intHeader.CheckHeader();

                GridImport grdImport = new GridImport(ReferenceManager.GetSmContainerImage());
                grdImport.GetVar();
                grdImport.Close();
                 * */
            }
            catch (Exception ex)
            {
                MessageBox.Show("An error occured during Grid phases. Reason: " + ex.Message,
                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }


    }
}
